package org.svnadmin.service.svn;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.svnadmin.constant.Constants;
import org.svnadmin.dao.*;
import org.svnadmin.entity.Pj;
import org.svnadmin.entity.PjAuth;
import org.svnadmin.entity.PjGrUsr;
import org.svnadmin.entity.Usr;
import org.svnadmin.util.I18N;

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 导出svn配置信息服务层定义
 *
 * @author hewenjie
 * @data 2021/6/21
 */
public abstract class SvnService {

    public static final String BEAN_NAME = "collabNetSvnService";
    private  Logger LOG;

    /**
     * 项目DAO
     */
    private PjDao pjDao;

    /**
     * 用户DAO
     */
    private UsrDao usrDao;

    /**
     * 项目组DAO
     */
    private PjGrDao pjGrDao;

    /**
     * 项目组用户DAO
     */
    private PjGrUsrDao pjGrUsrDao;

    /**
     * 项目权限DAO
     */
    private PjAuthDao pjAuthDao;

    protected void init(PjDao pjDao, UsrDao usrDao, PjGrDao pjGrDao, PjGrUsrDao pjGrUsrDao, PjAuthDao pjAuthDao, Logger logger){
         this.pjDao = pjDao;
         this.usrDao = usrDao;
         this.pjGrDao = pjGrDao;
         this.pjGrUsrDao = pjGrUsrDao;
         this.pjAuthDao = pjAuthDao;
         this.LOG = logger;
    }

    /**
     * 导出到配置文件
     *
     * @param pj 项目id
     */
    public synchronized void exportConfig(String pj) {
        this.exportConfig(this.pjDao.get(pj));
    }

    /**
     * 导出到配置文件
     *
     * @param pj 项目
     */
    public synchronized void exportConfig(Pj pj) {
        if (pj == null) {
            return;
        }
        File parent = new File(pj.getPath());
        if (!parent.exists() || !parent.isDirectory()) {
            throw new RuntimeException(I18N.getLbl("svn.notFoundResp", "找不到仓库 路径{0}",new Object[]{pj.getPath()}));
        }
        if (Constants.HTTP.equalsIgnoreCase(pj.getType())) {// HTTP(单库) SVNPath
            this.exportHTTP(pj);
        } else if (Constants.HTTP_MUTIL.equalsIgnoreCase(pj.getType())) {// HTTP(多库)
            // SVNParentPath
            File root = new File(pj.getPath()).getParentFile();
            this.exportHTTPMutil(root);
        } else if (Constants.SVN.equalsIgnoreCase(pj.getType())) {// SVN
            this.exportSVN(pj);
        }
    }

    /**
     * 导出svn协议的配置信息
     *
     * @param pj
     *            项目
     */
    private void exportSVN(Pj pj) {
        // 项目的用户
        List<Usr> usrList = this.usrDao.getList(pj.getPj());
        // 项目的用户组
        Map<String, List<PjGrUsr>> pjGrUsrMap = this.getPjGrUsrs(pj.getPj());
        // 项目的权限
        Map<String, List<PjAuth>> pjAuthMap = this.getPjAuths(pj.getPj());

        this.exportSvnConf(pj);
        this.exportPasswdSVN(pj, usrList);
        this.exportAuthz(pj, pjGrUsrMap, pjAuthMap);
    }

    /**
     * 导出http(单库)的配置信息
     *
     * @param pj
     *            项目
     */
    private void exportHTTP(Pj pj) {
        // 项目的用户
        List<Usr> usrList = this.usrDao.getList(pj.getPj());
        // 项目的用户组
        Map<String, List<PjGrUsr>> pjGrUsrMap = this.getPjGrUsrs(pj.getPj());
        // 项目的权限
        Map<String, List<PjAuth>> pjAuthMap = this.getPjAuths(pj.getPj());

        this.exportSVNPathConf(pj);
        this.exportPasswdHTTP(pj, usrList);
        this.exportAuthz(pj, pjGrUsrMap, pjAuthMap);
    }

    /**
     * 导出http(多库)的配置信息
     *
     * @param root
     *            svn root
     */
    private void exportHTTPMutil(File root) {
        String svnRoot = StringUtils.replace(root.getAbsolutePath(), "\\", "/");
        if (!svnRoot.endsWith("/")) {
            svnRoot += "/";
        }
        // 和这个项目在同一个父目录的所有项目的用户
        List<Usr> usrList = this.usrDao.getListByRootPath(svnRoot);
        // 和这个项目在同一个父目录的所有项目的用户组
        Map<String, List<PjGrUsr>> pjGrUsrMap = this
                .getPjGrUsrsByRootPath(svnRoot);
        // 和这个项目在同一个父目录的所有项目的权限
        Map<String, List<PjAuth>> pjAuthMap = this
                .getPjAuthsByRootPath(svnRoot);

        this.exportSVNParentPathConf(root);

        this.exportPasswdHTTPMutil(root, usrList);

        this.exportAuthzHTTPMutil(root, pjGrUsrMap, pjAuthMap);
    }

    /**
     * 获取有相同svn root的项目的权限列表
     *
     * @param rootPath svn root
     * @return 有相同svn root的项目的权限列表
     */
    protected Map<String, List<PjAuth>> getPjAuthsByRootPath(String rootPath) {
        Map<String, List<PjAuth>> results = new LinkedHashMap<String, List<PjAuth>>();// <res,List<PjAuth>>
        List<PjAuth> pjAuthList = this.pjAuthDao.getListByRootPath(rootPath);
        // 格式化返回数据
        for (PjAuth pjAuth : pjAuthList) {
            List<PjAuth> authList = results.get(pjAuth.getRes());
            if (authList == null) {
                authList = new ArrayList<PjAuth>();
                results.put(pjAuth.getRes(), authList);
            }
            authList.add(pjAuth);
        }
        return results;
    }

    /**
     * 获取项目的权限列表
     *
     * @param pj 项目
     * @return 项目的权限列表
     */
    protected Map<String, List<PjAuth>> getPjAuths(String pj) {
        Map<String, List<PjAuth>> results = new LinkedHashMap<String, List<PjAuth>>();// <res,List<PjAuth>>
        List<PjAuth> pjAuthList = this.pjAuthDao.getList(pj);
        // 格式化返回数据
        for (PjAuth pjAuth : pjAuthList) {
            List<PjAuth> authList = results.get(pjAuth.getRes());
            if (authList == null) {
                authList = new ArrayList<PjAuth>();
                results.put(pjAuth.getRes(), authList);
            }
            authList.add(pjAuth);

        }
        return results;
    }

    /**
     * 获取项目的组列表
     *
     * @param pj 项目
     * @return 项目的组列表
     */
    protected Map<String, List<PjGrUsr>> getPjGrUsrs(String pj) {
        Map<String, List<PjGrUsr>> results = new LinkedHashMap<String, List<PjGrUsr>>();// <gr,List<PjGrUsr>>
        List<PjGrUsr> pjGrUsrs = this.pjGrUsrDao.getList(pj);

        // 格式化返回数据
        for (PjGrUsr pjGrUsr : pjGrUsrs) {
            List<PjGrUsr> grUsrList = results.get(pjGrUsr.getGr());
            if (grUsrList == null) {
                grUsrList = new ArrayList<PjGrUsr>();
                results.put(pjGrUsr.getGr(), grUsrList);
            }
            grUsrList.add(pjGrUsr);
        }

        return results;
    }

    /**
     * 获取有相同svn root的项目的权限列表
     *
     * @param rootPath svn root
     * @return 有相同svn root的项目的权限列表
     */
    protected Map<String, List<PjGrUsr>> getPjGrUsrsByRootPath(String rootPath){
        Map<String, List<PjGrUsr>> results = new LinkedHashMap<String, List<PjGrUsr>>();// <pj_gr,List<PjGrUsr>>

        List<PjGrUsr> pjGrUsrs = this.pjGrUsrDao.getListByRootPath(rootPath);

        // 格式化返回数据
        for (PjGrUsr pjGrUsr : pjGrUsrs) {
            String key = pjGrUsr.getPj() + "_" + pjGrUsr.getGr();
            List<PjGrUsr> grUsrList = results.get(key);// 项目ID_组ID see: Issue 4
            if (grUsrList == null) {
                grUsrList = new ArrayList<PjGrUsr>();
                results.put(key, grUsrList);
            }
            grUsrList.add(pjGrUsr);
        }
        return results;
    }

    /**
     * 输出http多库方式的密码文件
     *
     * @param root      svn root
     * @param usrList   所有用户列表
     */
    abstract void exportPasswdHTTPMutil(File root, List<Usr> usrList);

    /**
     * 输出http单库方式的密码文件
     *
     * @param pj        项目
     * @param usrList   项目用户列表
     */
    abstract void exportPasswdHTTP(Pj pj, List<Usr> usrList);

    /**
     * 输出svn方式的密码文件
     *
     * @param pj        项目
     * @param usrList   项目用户列表
     */
    abstract void exportPasswdSVN(Pj pj, List<Usr> usrList);

    /**
     * 输出http多库方式的权限文件
     *
     * @param root  svn root
     * @param pjGrUsrMap   所有的项目组用户列表
     * @param resMap       所有的权限列表
     */
    abstract void exportAuthzHTTPMutil(File root, Map<String, List<PjGrUsr>> pjGrUsrMap, Map<String, List<PjAuth>> resMap);

    /**
     * 输出权限配置文件
     *
     * @param pj 项目
     * @param pjGrUsrMap 项目的组列表
     * @param resMap 项目的权限列表
     */
    abstract void exportAuthz(Pj pj, Map<String, List<PjGrUsr>> pjGrUsrMap, Map<String, List<PjAuth>> resMap);

    /**
     * 输出svn方式的svnserve.conf
     *
     * @param pj 项目
     */
    abstract void exportSvnConf(Pj pj);


    /**
     * 输出http单库方式的httpd.conf文件
     *
     * @param pj 项目
     */
    abstract void exportSVNPathConf(Pj pj);


    /**
     * 输出http多库方式的httpd.conf文件
     *
     * @param root svn root
     */
    abstract void exportSVNParentPathConf(File root);

    /**
     * 获取SVN所有用户信息
     *
     * @return List<Usr>
     */
    public abstract List<Usr> getSvnUserList();

    /**
     * 添加同步用户信息到SVN
     *
     * @param usr Usr
     * @param state 1 添加，2 删除，3 修改密码
     * return 0 添加用户成功 1 添加用户失败
     *        2 删除用户成功 3 删除用户失败
     *        4 修改密码成功 5 修改密码失败
     */
    public abstract int synSvnUseConfig(Usr usr,int state);

    /**
     * 写文件流
     *
     * @param outFile 输出文件
     * @param contents 内容
     */
     protected void write(File outFile, String contents){
         BufferedWriter writer = null;
         try {
             if (contents == null) {
                 contents = "";
             }
             if (!outFile.getParentFile().exists()) {
                 outFile.getParentFile().mkdirs();
             }
             writer = new BufferedWriter(new OutputStreamWriter(
                     new FileOutputStream(outFile), "UTF-8"));// UTF-8 without
             // BOM
             writer.write(contents);
             LOG.debug(outFile);
         } catch (Exception e) {
             e.printStackTrace();
             throw new RuntimeException(e.getMessage());
         } finally {
             if (writer != null) {
                 try {
                     writer.flush();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
                 try {
                     writer.close();
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
             }
         }
     }


}
